#include "StdDevice_UART.h"
#include "StdDevice_common.h"
#define LOG __platform_printf

static pika_dev* _get_dev(PikaObj* self) {
    pika_dev* dev = PIKA_HAL_OBJ2DEV(self);
    if (NULL != dev) {
        return dev;
    }
    dev = pika_hal_open(PIKA_HAL_UART, obj_getStr(self, "name"));
    if (NULL == dev) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open '%s' failed.", obj_getStr(self, "name"));
        return NULL;
    }
    obj_setPtr(self, "pika_dev", dev);
    return dev;
}

static void _free_dev(pika_dev* dev){
    if (NULL != dev && NULL != dev->ioctl_config) {
        pikaFree(dev->ioctl_config, sizeof(pika_hal_UART_config));
        dev->ioctl_config = NULL;
    }
    if (NULL != dev) {
        pikaFree(dev, sizeof(pika_dev));
    }
}

void StdDevice_UART___init__(PikaObj *self, char* name){
    obj_setStr(self, "name", name);
    obj_setPtr(self, "pika_dev", NULL);
}

void StdDevice_UART_open(PikaObj *self, int baudrate, int data_bits, int stop_bits, int parity){
    pika_dev* dev = _get_dev(self);
    pika_hal_UART_config cfg = {0};
    cfg.baudrate = baudrate;
    cfg.stop_bits = stop_bits;
    cfg.parity = parity;
    cfg.data_bits = data_bits;

    int err = -1;
    err = pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg);
    if (err != 0) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open '%s' failed.", obj_getStr(self, "name"));
        return;
    }
    err = pika_hal_ioctl(dev, PIKA_HAL_IOCTL_ENABLE);
    if (err != 0) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open '%s' failed.", obj_getStr(self, "name"));
        return;
    }
    
}

void StdDevice_UART_close(PikaObj *self){
    pika_dev* dev = _get_dev(self);
    pika_hal_UART_config* cfg = (pika_hal_UART_config*)dev->ioctl_config;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_DISABLE);
    pika_hal_close(dev);
    obj_setPtr(self, "pika_dev", NULL);
}

void StdDevice_UART_write(PikaObj *self, uint8_t* data, int length){
    pika_dev* dev = _get_dev(self);
    int res = pika_hal_write(dev, data, length);
    if (res < 0){
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] write fail.");
        return;
    }
}

Arg* StdDevice_UART_read(PikaObj *self, int length){
    #if 0
    obj_setBytes(self, "_readData", NULL, length + 1);
    uint8_t* buff = obj_getBytes(self, "_readData");
    pika_dev* dev = _get_dev(self);
    int len_get = pika_hal_read(dev, buff, length);
    obj_setBytes(self, "readData", buff, len_get);
    return arg_copy(obj_getArg(self, "readData"));
    #endif

    #if 1
    uint8_t* databuff = pikaMalloc(length + 1); // 我猜测length+1可能是为了给字符串加一个\0
    if (NULL == databuff) {
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] not enough memory.");
        return NULL;
    }
    pika_dev* dev = _get_dev(self);
    int len_get = pika_hal_read(dev, databuff, length);
    if (len_get < 0){
        pikaFree(databuff, length + 1);
        return arg_newNone();
    }
    Arg* bytes_obj = arg_newBytes(databuff, len_get);
    pikaFree(databuff, length + 1);
    return bytes_obj;
    #endif

   
}


void StdDevice_UART_enable_IT(PikaObj *self, int irq, Arg* evt_cbk){
#if PIKA_EVENT_ENABLE
    pika_dev* dev = _get_dev(self);
    _StdDevice_setCallback(self, evt_cbk, (uintptr_t)dev);
    /* regist event to pika_hal */
    pika_hal_UART_config cfg_cb = {0};
    cfg_cb.event_callback = _StdDevice_UART_event_handler;
    cfg_cb.event_callback_filter = irq;
    cfg_cb.event_callback_ena = PIKA_HAL_EVENT_CALLBACK_ENA_ENABLE;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb);
#else
    obj_setErrorCode(self, 1);
    obj_setSysOut(self, "[error] PIKA_EVENT_ENABLE is disabled.");
#endif
}

void StdDevice_UART_disable_IT(PikaObj *self, int irq){
    pika_dev* dev = _get_dev(self);
    _StdDevice_CancelCallback(self, (uintptr_t)dev);
    /* regist event to pika_hal */
    pika_hal_UART_config cfg_cb = {0};
    cfg_cb.event_callback = NULL;
    cfg_cb.event_callback_filter = irq;
    cfg_cb.event_callback_ena = PIKA_HAL_EVENT_CALLBACK_ENA_DISABLE;
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb);
}

void StdDevice_UART_remap(PikaObj *self, char* tx_name, char *rx_name){
    pika_dev* dev = _get_dev(self);
    pika_hal_UART_config cfg_cb = {0};
    cfg_cb.TX = pika_hal_open(PIKA_HAL_GPIO, tx_name);
    if (cfg_cb.TX == NULL){
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open '%s' failed.", tx_name);
        return;
    }
    cfg_cb.RX = pika_hal_open(PIKA_HAL_GPIO, rx_name);
    if (cfg_cb.RX == NULL){
        // pikaFree(cfg_cb.TX, sizeof(pika_dev));
        _free_dev(cfg_cb.TX);
        obj_setErrorCode(self, PIKA_RES_ERR_RUNTIME_ERROR);
        obj_setSysOut(self, "[ERROR] open '%s' failed.", rx_name);
        return;
    }
    pika_hal_ioctl(dev, PIKA_HAL_IOCTL_CONFIG, &cfg_cb);
    // pikaFree(cfg_cb.TX, sizeof(pika_dev));
    // pikaFree(cfg_cb.RX, sizeof(pika_dev));
    _free_dev(cfg_cb.TX);
    _free_dev(cfg_cb.RX);
}

char* StdDevice_UART_get_name(PikaObj *self){
    return obj_getStr(self, "name");
}

void StdDevice_UART___del__(PikaObj *self){
    pika_dev* dev = PIKA_HAL_OBJ2DEV(self);
    _free_dev(dev);
    // if (NULL != dev && NULL != dev->ioctl_config) {
    //     pikaFree(dev->ioctl_config, sizeof(pika_hal_UART_config));
    //     dev->ioctl_config = NULL;
    // }
    // if (NULL != dev) {
    //     pikaFree(dev, sizeof(pika_dev));
    // }
}